package com.lxw.report.meta.query.queryer;

import com.lxw.report.engine.dataModel.column.SheetColumn;
import com.lxw.report.engine.dataModel.report.*;
import com.lxw.report.engine.enums.DbColumnTypeEnum;
import com.lxw.report.meta.entity.DataBase;
import com.lxw.report.meta.enums.DbTypeEnum;
import com.lxw.report.meta.utils.JdbcUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

/**
 * 查询器
 */
public abstract class AbstractQueryer {
    private static Logger logger = LoggerFactory.getLogger(AbstractQueryer.class);
    private DataBase dataBase;
    protected AbstractQueryer(DataBase dataBase) {
        this.dataBase = dataBase;
    }

    /**
     * 数据集页面查询字段信息
     * @param sqlText
     * @return
     */
    public List<SheetColumn> parseMetaDataColumns(String sqlText) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        List<SheetColumn> columns = null;
        try {
            logger.info("查询报表元数据的 SQL:{},", sqlText);
            conn = this.getJdbcConnection();
            stmt = conn.createStatement();
            rs = stmt.executeQuery(this.preprocessSqlText(sqlText));
             ResultSetMetaData rsMataData = rs.getMetaData();
             int count = rsMataData.getColumnCount();
            columns = new ArrayList<>(count);
            for (int i = 1; i <= count; i++) {
                SheetColumn column = new SheetColumn();
                column.setSqlColumnName(rsMataData.getColumnLabel(i));
                column.setDbColumnType(DbColumnTypeEnum.valueOf(rsMataData.getColumnTypeName(i).toUpperCase()));
                columns.add(column);
            }
        } catch ( SQLException ex) {
            throw new RuntimeException(ex);
        } finally {
            JdbcUtil.releaseJdbcResource(conn, stmt, rs);
        }
        return columns;
    }

    /**
     * 查询参数中含有下拉参数且来源为SQL  则执行查询
     * @param sqlText
     * @return
     */
    public List<ReportQueryParamItem> parseQueryParamItems(String sqlText) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        HashSet<String> set = new HashSet<>();
        List<ReportQueryParamItem> rows = new ArrayList<>();
        try {
            logger.info("查询条件的 sql 为 {}",sqlText);
            conn = this.getJdbcConnection();
            stmt = conn.createStatement();
            rs = stmt.executeQuery(sqlText);
            while (rs.next()) {
                String name = rs.getString("name");
                String text = rs.getString("text");
                name = (name == null) ? "" : name.trim();
                text = (text == null) ? "" : text.trim();
                if (!set.contains(name)) {
                    set.add(name);
                }
                rows.add(new ReportQueryParamItem(name, text));
            }
        } catch ( SQLException ex) {
            throw new RuntimeException(ex);
        } finally {
            JdbcUtil.releaseJdbcResource(conn, stmt, rs);
        }
        return rows;
    }
    //获取每一行的数据并按照列转换为 一个个单元格,拼接改行的左侧维度列的key值
    public List<ReportDataRow> getReportDataRowsBySqlAndColumns(String sqlText,List<ReportColumn> dataReportColumnList) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        logger.info("数据原始SQL为  ------------->  {}",sqlText);
        String preprocessSqlText=this.preprocessSqlText(sqlText);
        logger.info("经过Queryer处理之后的SQL为  ------------->  {}",sqlText);
        try {
            conn = this.getJdbcConnection();
            stmt = conn.createStatement();
            rs = stmt.executeQuery(preprocessSqlText);
            List<ReportDataRow> reportMetaDataRowList=new ArrayList<>();
            while (rs.next()) {
                ReportDataRow reportDataRow = new ReportDataRow();
                for (ReportColumn column : dataReportColumnList) {
                    Object value = rs.getObject(column.getSqlColumnName());
                    reportDataRow.add(new ReportDataCell(column, column.getSqlColumnName(), value));
                }
                reportMetaDataRowList.add(reportDataRow);
            }
            return reportMetaDataRowList;
        } catch ( Exception ex) {
            logger.error(String.format("sql执行出错，SqlText: {}，Msg: {}", preprocessSqlText, ex));
            throw new RuntimeException(ex);
        } finally {
            JdbcUtil.releaseJdbcResource(conn, stmt, rs);
        }
    }

    /**
     * 预处理获取报表列集合的sql语句，
     * 在这里可以拦截全表查询等sql， 因为如果表的数据量很大，将会产生过多的内存消耗，甚至性能问题
     *
     * @param sqlText 原sql语句
     * @return 预处理后的sql语句
     */
    protected String preprocessSqlText( String sqlText) {
        return sqlText;
    }

    /**
     * 获取当前报表查询器的JDBC Connection对象
     *
     * @return Connection
     */
    protected Connection getJdbcConnection() {
        try {
            Class.forName(DbTypeEnum.getDriverByName(this.dataBase.getType()));
            return JdbcUtil.getDataSource(this.dataBase).getConnection();
        } catch ( Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}
